热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

数目|动量_深度学习基础:4.Pytorch搭建基础网络模型

篇首语:本文由编程笔记#小编为大家整理,主要介绍了深度学习基础:4.Pytorch搭建基础网络模型相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了深度学习基础:4.Pytorch搭建基础网络模型相关的知识,希望对你有一定的参考价值。




这个专栏停更了一段时间,现在重新开始,巩固基础才能看懂复杂代码。



Torch基本架构

使用Pytorch之前,首先要理清楚Pytorch基本架构。
Pytorch的核心库是torch,根据不同领域细分可以分成计算机视觉、自然语言处理和语音处理,这三个领域分别有自己对应的库,即torchvision、torchtext、torchaudio。


核心库Torch中,根据功能又可以细分成下面几个模块。


正向传播结构

下面就用Pytorch搭建一个简单的正向传播结构。

首先导库,这里需要三个库,torch基本库不必说,nn即neural network,包含了神经网络结构的基本元素。functional 包含了损失函数和激活函数。

import torch
import torch.nn as nn
from torch.nn import functional as F

之后进行数据生成
这里manual_seed是固定人为的随机种子,因为不固定该值,每次运行时神经网络各层的初始权重/偏置会进行随机初始化,导致结果不稳定。
X是生成(500,20)的数据,注意必须指定其数据格式为浮点型(float32),否则默认为整型。
y是随机生成500条(0,3]之间的数,注意y也是浮点型,因为在后面损失函数计算时需要浮点型数据。

torch.random.manual_seed(103)
X = torch.rand((500,20), dtype=torch.float32)
y = torch.randint(low=0,high=3,size=(500,1), dtype=torch.float32)

接下来就到了最核心的搭建网络结构模块


  • 1、定义模型类,注意要继承于nn.Module
  • 2、在初始化函数中继承父类的初始化函数 super(Model,self).__init__(),这是由于python的继承机制不会继承父类的 __init__
  • 3、指定输入输出神经元数目in_featuresout_features,这并不是必须的,但是如果把输入输出作为参数进行传递,会增强模型的通用性。
  • 4、构造Linear线性层,注意一个线性层输出和下一个线性层的输入个数需相等,否则无法计算(原理上就是矩阵相乘)
  • 5、构造forward函数,实现前向传播过程,指定每一层的输入输出和激活函数。

class Model(nn.Module):
def __init__(self,in_features=10, out_features=2):
"""
in_features: 输入该神经网络的特征数目(输入层上的神经元的数目)
out_features:神经网络的输出的数目(输出层上的神经元的数目)
"""

super(Model,self).__init__()
self.linear1 = nn.Linear(in_features,13,bias=True)
self.linear2 = nn.Linear(13,8,bias=True)
self.output = nn.Linear(8,out_features,bias=True)

def forward(self,x): #神经网络的向前传播
z1 = self.linear1(x)
sigma1 = torch.relu(z1)
z2 = self.linear2(sigma1)
sigma2 = torch.sigmoid(z2)
z3 = self.output(sigma2)
sigma3 = F.softmax(z3,dim=1)
return sigma3

之后实例化网络,注意在此之前要限定输入输出的个数,这里选择输入即X的特征维度20,输出y不同的数值(假设为分类问题,输出不同的类别)

input_ = X.shape[1]
output_ = len(y.unique())
net = Model(in_features=input_, out_features = output_)

调用模型,实现正向传播有下面两种书写方式:

# 方式一
y_hat = net.forward(X)
# 方式二
y_hat = net(X)

两者的区别是方式一只会调用forward函数内容,方式二回调用除 __init__之外的所有函数内容,因此更推荐第一种写法。
这样执行之后,输入向量维度为(500,20),输出结果为(500,3),即对每一条数据都根据20个特征得到了分类结果。

除此之外,可以用下面的语句查看每一层的参数。比如,查看linear1层的权重和偏置。

# 查看权重
net.linear1.weight
# 查看偏置
net.linear1.bias

使用net.linear1.weight.shape查看linear1层的维度,输出为(13,20),然而linear1层的输入为20,输出为13,这是由于在公式计算中,权重w会被转置再进行矩阵乘法运算。


损失函数

有了正向传播结构之后,就自然需要计算损失,反向传播。在此之前,有必要先了解一些损失函数的API。


回归损失函数

对于回归问题,比较常见的损失函数是SSEMSE,两者的公式如下:


在Pytoch中,可以这样进行调用。

from torch.nn import MSELoss
# 生成随机数据
yhat = torch.randn(size=(50,),dtype=torch.float32)
y = torch.randn(size=(50,),dtype=torch.float32)
# SSE
criterion = MSELoss(reduction = "sum")
loss = criterion(yhat,y)
# MSE
criterion = MSELoss(reduction = "mean")
loss = criterion(yhat,y)

分类损失函数

对于分类问题,最常采用的是交叉熵损失,比如二分类交叉熵损失函数如下:

Pytorch中,BCELossBCEWithLogitsLoss均能实现此功能,但后者的精度更高,不过一般来说,BCELoss基本够用。

from torch.nn import BCELoss, BCEWithLogitsLoss
# 生成随机数据
yhat = torch.randint(low=0,high=2,size=(10,1),dtype=torch.float32)
y = torch.randint(low=0,high=2,size=(10,1),dtype=torch.float32)
# 方式一
criterion = BCELoss()
loss = criterion(yhat,y)
# 方式二
criterion = BCEWithLogitsLoss()
loss = criterion(yhat,y)

MSELoss类似,BCELoss也有summean可选参数,功能和前面类似。

对于多分类问题,Pytorch提供了CrossEntropyLoss这个函数,使用实例如下:

from torch.nn import CrossEntropyLoss
# 生成随机数据
yhat = torch.randint(low=0,high=2,size=(10,2),dtype=torch.float32)
y = torch.randint(low=0,high=2,size=(10,),dtype=torch.float32)
# 多元交叉熵损失
criterion = CrossEntropyLoss()
loss = criterion(yhat, y.long())

使用注意:1、yhat必须>=2维,如果是1维数据会报错。2、CrossEntropyLoss计算时要求标签必须是整型数据,因此用y.long()将浮点型转换成整型。


实现反向传播

有了损失函数之后,在Pytorch中就可以用一行命令实现反向传播,即loss.backward()
把损失函数和反向传播添加到前向传播过程中,就形成了一轮简单的神经网络训练过程。

import torch
import torch.nn as nn
from torch.nn import functional as F
#确定数据
torch.random.manual_seed(103)
X = torch.rand((500,20), dtype=torch.float32)
y = torch.randint(low=0,high=3,size=(500,1), dtype=torch.float32)
input_ = X.shape[1]
output_ = len(y.unique())
class Model(nn.Module):
def __init__(self,in_features=10, out_features=2):
"""
in_features: 输入该神经网络的特征数目(输入层上的神经元的数目)
out_features:神经网络的输出的数目(输出层上的神经元的数目)
"""

super(Model,self).__init__()
self.linear1 = nn.Linear(in_features,13,bias=True)
self.linear2 = nn.Linear(13,8,bias=True)
self.output = nn.Linear(8,out_features,bias=True)

def forward(self,x): #神经网络的向前传播
z1 = self.linear1(x)
sigma1 = torch.relu(z1)
z2 = self.linear2(sigma1)
sigma2 = torch.sigmoid(z2)
z3 = self.output(sigma2)
sigma3 = F.softmax(z3,dim=1)
return sigma3

net = Model(in_features=input_, out_features = output_) # 实例化神经网络
y_hat = net.forward(X) # 向前传播
criterion = nn.CrossEntropyLoss()
loss = criterion(y_hat,y.reshape(500).long())
loss.backward()
# loss.backward(retain_graph=True)

注意:Pytorch的反向传播底层是基于一个动态的计算图,每次执行完backward之后,这个计算图会从内存中自动销毁,如果想要保留这张图,以便进行多次反向传播,可以设置参数retain_graph=True
上述模型计算图可视化如下:


使用优化器

上面实现了一个最基本正向传播和反向传播的过程,然而,如果要应用更加复杂优化算法,直接手写就非常麻烦。Pytorch提供了一个优化器(optim),其内部封装了大量优化算法,可以方便开发者快速调用。

例如,实现随机梯度下降,可以调用optim的SGD接口,调用接口如下:

class torch.optim.SGD(params, lr=, momentum=0, dampening=0, weight_decay=0, nesterov=False)

相关参数解释:


参数描述
params (iterable)待优化参数的iterable或者是定义了参数组的dict
lr (float)学习率
momentum (float, 可选)动量因子(默认:0,通常设置为0.9,0.8)
weight_decay (float, 可选)权重衰减(L2惩罚)(默认:0)
dampening (float, 可选)动量的抑制因子(默认:0)
nesterov (bool, 可选)使用Nesterov动量(默认:False

optim更多接口参数解释,看到这篇博客记录比较详细,放置链接如下:
Link:https://blog.csdn.net/xq151750111/article/details/123602946

下面还是以之前的网络模型为例,实现一个带动量参数的SGD优化器

import torch
import torch.nn as nn
import torch.optim as optim
from torch.nn import functional as F
torch.manual_seed(103)
X = torch.rand((500,20),dtype=torch.float32) * 100
y = torch.randint(low=0,high=3,size=(500,),dtype=torch.float32)
lr = 0.1 # 学习率
gamma = 0.9 # 动量
class Model(nn.Module):
def __init__(self,in_features=10,out_features=2):
super(Model,self).__init__()
self.linear1 = nn.Linear(in_features,13,bias=True)
self.linear2 = nn.Linear(13,8,bias=True)
self.output = nn.Linear(8,out_features,bias=True)

def forward(self, x):
sigma1 = torch.relu(self.linear1(x))
sigma2 = torch.sigmoid(self.linear2(sigma1))
zhat = self.output(sigma2)
return zhat

input_ = X.shape[1] #特征的数目
output_ = len(y.unique()) #分类的数目
net = Model(in_features=input_, out_features=output_) #实例化网络
criterion = nn.CrossEntropyLoss() #定义损失函数
opt = optim.SGD(net.parameters(),lr = lr,momentum = gamma)
yhat = net.forward(X)
loss = criterion(yhat, y.long()) #计算损失函数
loss.backward()
opt.step() #走一步,更新权重w,更新动量v
opt.zero_grad() #清除原来储存好的,基于上一个坐标点计算的梯度,为下一次计算梯度腾出空间

这一段代码就是实现了梯度下降中的一步,加上循环,就形成了常见的深度学习过程。


数据加载器

在数据量少时,上面的代码能够完成训练。然而,当数据量变大时,就比较依赖硬件性能。比如,如果使用的CPU版本的Pytorch,数据会被加载进内存,如果内存无法容纳所有数据就会产生爆内存的问题,严重点可能会导致死机。如果使用GPU版本的Pytorch,数据可以选择加载进显存,如果显存不够大,会产生爆显存的Bug。

为了解决这个问题,可以将大批量的数据进行切分,每次只送一批数据到模型中进行训练,这批数据的大小就叫batch_size

Pytorch为了数据切分提供了两个工具,TensorDatasetDataLoader
之前输入模型的数据和标签是分开的,但是在后面的数据加载器DataLoader中,需要输入数据和标签的整体。python中的zip函数能够实现打包功能,Pytorch的TensorDataset函数功能也类似。不过对于tensor数据而言,pytorch提供的函数通常比python原生函数运算更快一些。

TensorDataset的使用示例如下:

from torch.utils.data import TensorDataset
a = torch.randn(500,3,4,5) #四维数据 - 图像
b = torch.randn(500,1) #二维数据 - 标签
c = TensorDataset(a,b)

直接打印c,不会输出具体的值,可以用下面的方式进行查看:

for x in c:
print(x)
break

输出c中的第一项如图所示:

里面包含两个tensor,第一个是数据,第二个是标签。

有了tensor之后,就可以直接将数据输入到DataLoader之中。DataLoader是处理训练前的数据加载器,它可以接受任意形式的数组、张量作为输入,并把他们一次性转换为神经网络可以接入的tensor。

DataLoader有很多参数,这里使用三个:


  • batch_size
    指定每一批(batch)数据的大小
  • shuffle
    是否对数据进行打乱
  • drop_last
    是否将最后一批不满足batch_size大小的数据丢弃

from torch.utils.data import DataLoader
dataset = DataLoader(c
, batch_size = 120
, shuffle = True #随机打乱数据
, drop_last = True #是否舍弃最后一个batch
)

打印出每个TensorDataset大小查看:

for i in dataset:
print(i[0].shape) # i[0]是数据,i[1]是标签


如图所示,500条数据,每个batch_size为120并舍弃最后一个batch,因此输出四个batch。

在实际使用中,通常这样进行调用。

for batch_idx, (x,y) in enumerate(dataset):
yhat = net(x)
loss = criterion(yhat, y)
loss.backward()
opt.step()
opt.zero_grad()

推荐阅读
  • YOLOv7基于自己的数据集从零构建模型完整训练、推理计算超详细教程
    本文介绍了关于人工智能、神经网络和深度学习的知识点,并提供了YOLOv7基于自己的数据集从零构建模型完整训练、推理计算的详细教程。文章还提到了郑州最低生活保障的话题。对于从事目标检测任务的人来说,YOLO是一个熟悉的模型。文章还提到了yolov4和yolov6的相关内容,以及选择模型的优化思路。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 浏览器中的异常检测算法及其在深度学习中的应用
    本文介绍了在浏览器中进行异常检测的算法,包括统计学方法和机器学习方法,并探讨了异常检测在深度学习中的应用。异常检测在金融领域的信用卡欺诈、企业安全领域的非法入侵、IT运维中的设备维护时间点预测等方面具有广泛的应用。通过使用TensorFlow.js进行异常检测,可以实现对单变量和多变量异常的检测。统计学方法通过估计数据的分布概率来计算数据点的异常概率,而机器学习方法则通过训练数据来建立异常检测模型。 ... [详细]
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
  • 开源Keras Faster RCNN模型介绍及代码结构解析
    本文介绍了开源Keras Faster RCNN模型的环境需求和代码结构,包括FasterRCNN源码解析、RPN与classifier定义、data_generators.py文件的功能以及损失计算。同时提供了该模型的开源地址和安装所需的库。 ... [详细]
  • 本文介绍了Python语言程序设计中文件和数据格式化的操作,包括使用np.savetext保存文本文件,对文本文件和二进制文件进行统一的操作步骤,以及使用Numpy模块进行数据可视化编程的指南。同时还提供了一些关于Python的测试题。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 后台获取视图对应的字符串
    1.帮助类后台获取视图对应的字符串publicclassViewHelper{将View输出为字符串(注:不会执行对应的ac ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • Givenasinglylinkedlist,returnarandomnode'svaluefromthelinkedlist.Eachnodemusthavethe s ... [详细]
author-avatar
快乐碧云轩在江湖
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有